package com.bank.utils;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author: Lixy
 * @email: 1908598362@qq.com
 * @date: 2022/2/2 星期四 1:57
 */
public class zkDistributedLockUtil {

    private ZooKeeper zooKeeper;
    private String connectString = "112.74.85.215:2181";
    private int sessionTimeout = 50000;
    private CountDownLatch connectLatch = new CountDownLatch(1);
    private CountDownLatch watchlatch = new CountDownLatch(1);
    private String waitPath;
    private String currentNode;

    public zkDistributedLockUtil() throws IOException, InterruptedException, KeeperException {
        zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                    connectLatch.countDown();
                }
                if (watchedEvent.getType() == Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)) {
                    watchlatch.countDown();
                }
            }
        });
        connectLatch.await();

        Stat status = zooKeeper.exists("/locks", false);

        if (status == null) {
            zooKeeper.create("/locks", "locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }

    public void zkLock() throws Exception{
        try {
            currentNode = zooKeeper.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            List<String> children = zooKeeper.getChildren("/locks", false);
            if (children.size() == 1) {
                return;
            } else {
                Collections.sort(children);
                String thisNode = currentNode.substring("/locks/".length());
                int temp = children.indexOf(thisNode);
                if (temp == -1) {
                    throw new Exception("数据异常");
                } else if (temp == 0) {
                    return;
                } else {
                    waitPath = "/locks/" + children.get(temp - 1);
                    zooKeeper.getData(waitPath, true, null);
                    watchlatch.await();
                    return;
                }
            }
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public void unLock()  {
        try {
            zooKeeper.delete(currentNode, -1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
}
